using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TextEffect
{
    public class CTextEffect
    {
        #region Property
        public SpriteFont Font
        {
            get;
            set;
        }

        public Rectangle TextBox
        {
            get;
            set;
        }

        public Vector2 TextPosition
        {
            get;
            set;
        }

        public float TextPositionX
        {
            get
            {
                return TextPosition.X;
            }
            set
            {
                TextPosition = new Vector2(value, TextPosition.Y);
            }
        }

        public float TextPositionY
        {
            get
            {
                return TextPosition.Y;
            }
            set
            {
                TextPosition = new Vector2(TextPosition.X, value);
            }
        }

        public SpriteBatch SpriteBatch
        {
            get;
            set;
        }

        public String TypeWriterText
        {
            get;
            set;
        }

        public List<String> ListLineBoxText
        {
            get;
            set;
        }

        public String BoxText
        {
            get;
            set;
        }

        public bool IsVerticalBoxText
        {
            get;
            set;
        }

        public float VeclocityBoxText
        {
            get;
            set;
        }

        public String OgrinalTypeWriterText
        {
            get;
            set;
        }

        public int DelayInMilliseconds
        {
            get;
            set;
        }

        public bool IsDoneDrawingWriter
        {
            get;
            set;
        }

        public double TypeWriterTextLength
        {
            get;
            set;
        }

        #endregion

        #region Initialize

        public CTextEffect()
        {

        }

        public CTextEffect(SpriteBatch spriteBatch, SpriteFont font, Vector2 position, Viewport viewport)
        {
            SpriteBatch = spriteBatch;
            Font = font;
            TextPosition = position;
            TextBox = new Rectangle(0, 0, viewport.Width, viewport.Height);
        }

        public CTextEffect(SpriteBatch spriteBatch, SpriteFont font, Vector2 position, Rectangle textBox)
        {
            SpriteBatch = spriteBatch;
            Font = font;
            TextPosition = position;
            TextBox = textBox;
        }
        #endregion

        #region WrapText
        //Wrap text in a text box

        public String CreateWrapText(String text)
        {
            String line = String.Empty;
            String returnString = String.Empty;
            String[] wordArray = text.Split(' ');

            foreach (String word in wordArray)
            {
                if (Font.MeasureString(line + word).Length() > TextBox.Width)
                {
                    returnString = returnString + line + '\n';
                    line = String.Empty;
                }
                line = line + word + ' ';
            }

            return returnString + line;
        }

        public List<String> CreateListWrapText(String text)
        {
            List<String> list = new List<String>();
            String line = String.Empty;
            String[] wordArray = text.Split(' ');
            if (IsVerticalBoxText)
            {
                foreach (String word in wordArray)
                {
                    if (Font.MeasureString(line + word).Length() > TextBox.Width || word.Equals("\\n") || word.Equals(wordArray[wordArray.Count()-1]))
                    {
                        if(word.Equals(wordArray[wordArray.Count()-1]))
                        {
                            line+= word;
                        }
                        list.Add(line);
                        line = String.Empty;
                        
                    }
                    if (word.Equals("\\n"))
                        line = line + ' ';
                    else
                        line = line + word + ' ';
                }
            }
            else
            {
                list = text.Split(' ').ToList<String>();
                int listCount = list.Count;
                for (int i = 0; i < listCount; i++)
                    if (list[i].Equals("\\n"))
                    {
                        listCount--;
                        list.RemoveAt(i);
                    }
            }
            return list;
        }

        #endregion

        #region DrawAlphaString
        //Draw text with fade effect with opacity from 0 to 0 in vertical

        public void DrawAlphaString(String text, Vector2 position)
        {
            float alpha = 1f;
            float fadeValue = 1f / (text.Length * 1.2f);
            Vector2 oldPos = position;

            float rowSpacing = Font.MeasureString("Y").Y - 5f;

            for (int i = 0; i < text.Length; i++)
            {
                String character = text.Substring(i, 1);
                alpha -= fadeValue;

                SpriteBatch.DrawString(Font, character, position, Color.White * alpha);

                if (position.X < TextBox.Right - 10f)
                {
                    position.X += 1f + Font.MeasureString(character).X;
                }
                else
                {
                    position.X = oldPos.X;
                    position.Y += rowSpacing;
                }
            }
        }

        public void DrawAlphaString(String text, Vector2 position, Color color)
        {
            float alpha = 1f;
            float fadeValue = 1f / (text.Length * 1.2f);
            Vector2 oldPos = position;

            float rowSpacing = Font.MeasureString("Y").Y - 5f;

            for (int i = 0; i < text.Length; i++)
            {
                String character = text.Substring(i, 1);
                alpha -= fadeValue;

                SpriteBatch.DrawString(Font, character, position, color * alpha);

                if (position.X < TextBox.Right - 10f)
                {
                    position.X += 1f + Font.MeasureString(character).X;
                }
                else
                {
                    position.X = oldPos.X;
                    position.Y += rowSpacing;
                }
            }
        }

        public void DrawAlphaString(String text, Vector2 position, Color color, Color highlight)
        {
            float alpha = 1f;
            float fadeValue = 1f / (text.Length * 1.2f);
            Vector2 oldPos = position;

            float rowSpacing = Font.MeasureString("Y").Y - 5f;

            for (int i = 0; i < text.Length; i++)
            {
                String character = text.Substring(i, 1);
                alpha -= fadeValue;
                DrawStringHighlight(Font, character, position, color * alpha, highlight * alpha, 1);

                if (position.X < TextBox.Right - 10f)
                {
                    position.X += 1f + Font.MeasureString(character).X;
                }
                else
                {
                    position.X = oldPos.X;
                    position.Y += rowSpacing;
                }
            }
        }

        public void DrawAlphaString(String text, Vector2 position, Color color, Color highlight, float distanceHighlight)
        {
            float alpha = 1f;
            float fadeValue = 1f / (text.Length * 1.2f);
            Vector2 oldPos = position;

            float rowSpacing = Font.MeasureString("Y").Y - 5f;

            for (int i = 0; i < text.Length; i++)
            {
                String character = text.Substring(i, 1);
                alpha -= fadeValue;
                DrawStringHighlight(Font, character, position, color * alpha, highlight * alpha, distanceHighlight);

                if (position.X < TextBox.Right - 10f)
                {
                    position.X += 1f + Font.MeasureString(character).X;
                }
                else
                {
                    position.X = oldPos.X;
                    position.Y += rowSpacing;
                }
            }
        }

        #endregion

        #region DrawStringHighlight
        /// <summary>
        /// Draw text with highlight
        /// </summary>
        /// <param name="text"></param>
        /// <param name="position"></param>

        public void DrawStringHighlight(SpriteFont font, String text, Vector2 position)
        {
            SpriteBatch.DrawString(font, text, position + new Vector2(1, 1), Color.Black);
            SpriteBatch.DrawString(font, text, position, Color.White);
        }

        public void DrawStringHighlight(SpriteFont font, String text, Vector2 position, Color color, Color highlight)
        {
            SpriteBatch.DrawString(font, text, position + new Vector2(1, 1), highlight);
            SpriteBatch.DrawString(font, text, position, color);
        }

        public void DrawStringHighlight(SpriteFont font, String text, Vector2 position, Color color, Color highlight, float distanceHighlight)
        {
            SpriteBatch.DrawString(font, text, position + new Vector2(distanceHighlight, distanceHighlight), highlight);
            SpriteBatch.DrawString(font, text, position, color);
        }

        #endregion

        #region TypeWriter
        //Draw text with type writer effect. Need use UpdateTypeWriter Function in Update Function

        public void InitTypeWriter(String typeWriterText, int delayInMilliseconds)
        {
            IsDoneDrawingWriter = false;
            TypeWriterText = "";
            TypeWriterTextLength = 0;
            DelayInMilliseconds = delayInMilliseconds;
            OgrinalTypeWriterText = typeWriterText;
        }

        public void UpdateTypeWriter(GameTime gameTime)
        {
            if (!IsDoneDrawingWriter)
            {
                // instant
                if (DelayInMilliseconds == 0)
                {
                    TypeWriterText = OgrinalTypeWriterText;
                    IsDoneDrawingWriter = true;
                }
                else if (TypeWriterTextLength < OgrinalTypeWriterText.Length)
                {
                    TypeWriterTextLength = TypeWriterTextLength + gameTime.ElapsedGameTime.TotalMilliseconds / DelayInMilliseconds;

                    if (TypeWriterTextLength >= OgrinalTypeWriterText.Length)
                    {
                        TypeWriterTextLength = OgrinalTypeWriterText.Length;
                        IsDoneDrawingWriter = true;
                    }
                    TypeWriterText = OgrinalTypeWriterText.Substring(0, (int)TypeWriterTextLength);
                }
            }
        }

        #endregion

        #region LoadTextFromFile

        public List<String> LoadTextFromFile(String path)
        {
            List<string> lines = new List<string>();
            using (Stream fileStream = TitleContainer.OpenStream(path))
            {
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    String line = reader.ReadLine();
                    while (line != null)
                    {
                        lines.Add(line);
                        line = reader.ReadLine();
                    }
                }
            }
            return lines;
        }

        #endregion

        #region DrawAlphaBox
        //Draw text with effect like a film credit

        public void InitDrawAlphaBox(bool isVerticalBoxText, String textInBox, float velocity)
        {
            IsVerticalBoxText = isVerticalBoxText;
            ListLineBoxText = CreateListWrapText(textInBox);
            VeclocityBoxText = velocity;
            if (IsVerticalBoxText)
            {
                BoxText = CreateWrapText(textInBox);
                TextPosition = new Vector2(TextBox.X, TextBox.Y + TextBox.Height);
            }
            else
            {
                String[] wordArray = textInBox.Split(' ');
                for (int i = 0; i < wordArray.Count(); i++)
                {
                    BoxText += wordArray[i] + " ";
                }
                TextPosition = new Vector2(TextBox.X + TextBox.Width, TextBox.Y + TextBox.Height / 2.0f);
            }
        }

        public void UpdateDrawAlphaBox(GameTime gameTime)
        {
            if (IsVerticalBoxText)
            {
                Vector2 size = Font.MeasureString(BoxText);
                if (TextPositionY + size.Y > TextBox.Y)
                    TextPositionY-= VeclocityBoxText*gameTime.ElapsedGameTime.Milliseconds / 1000.0f;
                else
                {
                    TextPositionY = TextBox.Y + TextBox.Height;
                }
            }
            else
            {
                Vector2 size = Font.MeasureString(BoxText);
                if (TextPositionX + size.X > TextBox.X)
                    TextPositionX -= VeclocityBoxText * gameTime.ElapsedGameTime.Milliseconds / 1000.0f;
                else
                {
                    TextPositionX = TextBox.X + TextBox.Width;
                }
            }
        }

        public void UpdateDrawAlphaBox()
        {
            if (IsVerticalBoxText)
            {
                Vector2 size = Font.MeasureString(BoxText);
                if (TextPositionY + size.Y > TextBox.Y)
                    TextPositionY -= 1;
                else
                {
                    TextPositionY = TextBox.Y + TextBox.Height;
                }
            }
            else
            {
                Vector2 size = Font.MeasureString(BoxText);
                if (TextPositionX + size.X > TextBox.X)
                    TextPositionX -= 1;
                else
                {
                    TextPositionX = TextBox.X + TextBox.Width;
                }
            }
        }

        public void DrawAlphaBox()
        {
            float alpha = 0f;
            int listCount = ListLineBoxText.Count;
            if (IsVerticalBoxText)
            {
                float sizeLine = Font.MeasureString("Y").Y;
                for (int i = 0; i < listCount; i++)
                {
                    Vector2 currentPosition = new Vector2(TextPositionX +(TextBox.Width - Font.MeasureString(ListLineBoxText[i]).Length())/2.0f, TextPositionY + sizeLine * i);
                    if (currentPosition.Y < (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (currentPosition.Y - TextBox.Y) / (TextBox.Height / 2.0f);
                    else if (currentPosition.Y >= (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (TextBox.Y + TextBox.Height - currentPosition.Y) / (TextBox.Height / 2.0f);
                    if (currentPosition.Y > TextBox.Y && currentPosition.Y < TextBox.Y + TextBox.Height)
                        SpriteBatch.DrawString(Font, ListLineBoxText[i], currentPosition, Color.White * alpha);
                }
            }
            else
            {
                float sizeWord = 0;
                for (int i = 0; i < listCount; i++)
                {
                    if (i > 0)
                    {
                        sizeWord += Font.MeasureString(ListLineBoxText[i - 1] + ' ').X;
                    }
                    Vector2 currentPosition = new Vector2(TextPositionX + sizeWord, TextPositionY);
                    if (currentPosition.X < (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (currentPosition.X - TextBox.X) / (TextBox.Width / 2.0f);
                    else if (currentPosition.X >= (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (TextBox.X + TextBox.Width - currentPosition.X) / (TextBox.Width / 2.0f);
                    if (currentPosition.X > TextBox.X && currentPosition.X < TextBox.X + TextBox.Width)
                    {
                        SpriteBatch.DrawString(Font, ListLineBoxText[i], currentPosition, Color.White * alpha);
                    }
                }
            }
        }

        public void DrawAlphaBox(Color color)
        {
            float alpha = 0f;
            int listCount = ListLineBoxText.Count;
            if (IsVerticalBoxText)
            {
                float sizeLine = Font.MeasureString("Y").Y;
                for (int i = 0; i < listCount; i++)
                {
                    Vector2 currentPosition = new Vector2(TextPositionX + (TextBox.Width - Font.MeasureString(ListLineBoxText[i]).Length()) / 2.0f, TextPositionY + sizeLine * i);
                    if (currentPosition.Y < (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (currentPosition.Y - TextBox.Y) / (TextBox.Height / 2.0f);
                    else if (currentPosition.Y >= (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (TextBox.Y + TextBox.Height - currentPosition.Y) / (TextBox.Height / 2.0f);
                    if (currentPosition.Y > TextBox.Y && currentPosition.Y < TextBox.Y + TextBox.Height)
                    {
                        SpriteBatch.DrawString(Font, ListLineBoxText[i], currentPosition, color * alpha);
                    }
                }
            }
            else
            {
                float sizeWord = 0;
                for (int i = 0; i < listCount; i++)
                {
                    if (i > 0)
                    {
                        sizeWord += Font.MeasureString(ListLineBoxText[i - 1] + ' ').X;
                    }
                    Vector2 currentPosition = new Vector2(TextPositionX + sizeWord, TextPositionY);
                    if (currentPosition.X < (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (currentPosition.X - TextBox.X) / (TextBox.Width / 2.0f);
                    else if (currentPosition.X >= (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (TextBox.X + TextBox.Width - currentPosition.X) / (TextBox.Width / 2.0f);
                    if (currentPosition.X > TextBox.X && currentPosition.X < TextBox.X + TextBox.Width)
                    {
                        SpriteBatch.DrawString(Font, ListLineBoxText[i], currentPosition, color * alpha);
                    }
                }
            }
        }

        public void DrawAlphaBox(Color color, Color highlight)
        {
            float alpha = 0f;
            int listCount = ListLineBoxText.Count;
            if (IsVerticalBoxText)
            {
                float sizeLine = Font.MeasureString("Y").Y;
                for (int i = 0; i < listCount; i++)
                {
                    Vector2 currentPosition = new Vector2(TextPositionX + (TextBox.Width - Font.MeasureString(ListLineBoxText[i]).Length()) / 2.0f, TextPositionY + sizeLine * i);
                    if (currentPosition.Y < (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (currentPosition.Y - TextBox.Y) / (TextBox.Height / 2.0f);
                    else if (currentPosition.Y >= (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (TextBox.Y + TextBox.Height - currentPosition.Y) / (TextBox.Height / 2.0f);
                    if (currentPosition.Y > TextBox.Y && currentPosition.Y < TextBox.Y + TextBox.Height)
                    {
                        DrawStringHighlight(Font, ListLineBoxText[i], currentPosition, color*alpha, highlight*alpha);
                    }
                }
            }
            else
            {
                float sizeWord = 0;
                for (int i = 0; i < listCount; i++)
                {
                    if (i > 0)
                    {
                        sizeWord += Font.MeasureString(ListLineBoxText[i - 1] + ' ').X;
                    }
                    Vector2 currentPosition = new Vector2(TextPositionX + sizeWord, TextPositionY);
                    if (currentPosition.X < (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (currentPosition.X - TextBox.X) / (TextBox.Width / 2.0f);
                    else if (currentPosition.X >= (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (TextBox.X + TextBox.Width - currentPosition.X) / (TextBox.Width / 2.0f);
                    if (currentPosition.X > TextBox.X && currentPosition.X < TextBox.X + TextBox.Width)
                    {
                        DrawStringHighlight(Font, ListLineBoxText[i], currentPosition, color*alpha, highlight*alpha);
                    }
                }
            }
        }

        public void DrawAlphaBox(Color color, Color highlight, float distanceHighlight)
        {
            float alpha = 0f;
            int listCount = ListLineBoxText.Count;
            if (IsVerticalBoxText)
            {
                float sizeLine = Font.MeasureString("Y").Y;
                for (int i = 0; i < listCount; i++)
                {
                    Vector2 currentPosition = new Vector2(TextPositionX + (TextBox.Width - Font.MeasureString(ListLineBoxText[i]).Length()) / 2.0f, TextPositionY + sizeLine * i);
                    if (currentPosition.Y < (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (currentPosition.Y - TextBox.Y) / (TextBox.Height / 2.0f);
                    else if (currentPosition.Y >= (TextBox.Y + TextBox.Height / 2.0f))
                        alpha = (TextBox.Y + TextBox.Height - currentPosition.Y) / (TextBox.Height / 2.0f);
                    if (currentPosition.Y > TextBox.Y && currentPosition.Y < TextBox.Y + TextBox.Height)
                    {
                        DrawStringHighlight(Font, ListLineBoxText[i], currentPosition, color*alpha, highlight*alpha, distanceHighlight);
                    }
                }
            }
            else
            {
                float sizeWord = 0;
                for (int i = 0; i < listCount; i++)
                {
                    if (i > 0)
                    {
                        sizeWord += Font.MeasureString(ListLineBoxText[i - 1] + ' ').X;
                    }
                    Vector2 currentPosition = new Vector2(TextPositionX + sizeWord, TextPositionY);
                    if (currentPosition.X < (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (currentPosition.X - TextBox.X) / (TextBox.Width / 2.0f);
                    else if (currentPosition.X >= (TextBox.X + TextBox.Width / 2.0f))
                        alpha = (TextBox.X + TextBox.Width - currentPosition.X) / (TextBox.Width / 2.0f);
                    if (currentPosition.X > TextBox.X && currentPosition.X < TextBox.X + TextBox.Width)
                    {
                        DrawStringHighlight(Font, ListLineBoxText[i], currentPosition, color*alpha, highlight*alpha, distanceHighlight);
                    }
                }
            }
        }

        #endregion
    }
}
